﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Text.RegularExpressions;

namespace StringDefs.Phonetic
{
    using StringDefs.Common;
    
    public static class Phonetic
    {
        public enum PhoneticStyle { Soundex, NYSIIS };
    
     
        /// <summary>
        /// Returns the soundex code  
        /// </summary>
        /// <param name="word"></param>
        /// <returns></returns>
        public static string Soundex(this string word)
        {
            int i, j;
            char[] temp = new char[word.Length];
            temp[0] = word[0];
            for (i = 1, j = 1; i < word.Length; i++)
            {

                if (word[i] == word[i - 1])

                    i++;//This is to avoid repeatation of characters
                if (i == word.Length) break;

                if (word[i] != 'a' || word[i] != 'e' || word[i] != 'h' || word[i] != 'i'
                    || word[i] != 'o' || word[i] != 'u' || word[i] != 'w' || word[i] != 'y')
                {
                    if (word[i] == 'b' || word[i] == 'f' || word[i] == 'p' || word[i] == 'v')
                    {
                        temp[j] = '1';
                        j++;
                    }
                    if (word[i] == 'c' || word[i] == 'g' || word[i] == 'j'
                          || word[i] == 'k' || word[i] == 'q' || word[i] == 's'
                          || word[i] == 'x' || word[i] == 'z')
                    {
                        temp[j] = '2';
                        j++;
                    }
                    if (word[i] == 'd' || word[i] == 't')
                    {
                        temp[j] = '3';
                        j++;
                    }
                    if (word[i] == 'l')
                    {
                        temp[j] = '4';
                        j++;
                    }

                    if (word[i] == 'm' || word[i] == 'n')
                    {
                        temp[j] = '5';
                        j++;
                    }

                    if (word[i] == 'r')
                    {
                        temp[j] = '6';
                        j++;
                    }

                }
            }

            string code = new string(temp);
            if (code.IndexOf('\0') != -1)
                code = code.Substring(0, code.IndexOf('\0'));
            if (code.Length > 4)
                return code.Substring(0, 4);
            else
            {
                if (code.Length == 4)
                    return code;
                else
                    return code.PadRight(4, '0');
            }

        }
        /// <summary>
        /// 
        /// </summary>
        /// <param name="oneWord"></param>
        /// <param name="anotherWord"></param>
        /// <returns></returns>
        public static bool IsSameSoundex(this string oneWord, string anotherWord)
        {
            return Soundex(oneWord).Equals(Soundex(anotherWord));
        }

        private static string TranscodePrefix(string surname)
        {
            surname = surname.ToUpper();
            string nysiisCode = string.Empty;
            if (surname.StartsWith("MAC"))
                return  surname.Replace("MAC", "MCC");
            if (surname.StartsWith("KN"))
                return  surname.Replace("KN", "NN");
            if (surname.StartsWith("K"))
                return  surname.Replace("K", "C");
            if (surname.StartsWith("PH"))
                return surname.Replace("PH", "FF");
            if (surname.StartsWith("PF"))
                return surname.Replace("PF", "FF");
            if (surname.StartsWith("SCH"))
                return surname.Replace("SCH", "SSS");

            return surname;


        }
        private static string TranscodeSuffix(string surname)
        {
            if (surname.EndsWith ("EE"))
                return surname.Replace("EE", "Y");
            if (surname.EndsWith("IE"))
                return surname.Replace("IE", "Y");
            if (surname.EndsWith("DT"))
                return surname.Replace("DT", "D");
            if (surname.EndsWith("RT"))
                return surname.Replace("RT", "D");
            if (surname.EndsWith("RD"))
                return surname.Replace("RD", "D");
            if (surname.EndsWith("NT"))
                return surname.Replace("NT", "D");
            if (surname.EndsWith("ND"))
                return surname.Replace("ND", "D");

            return surname;            

        }
        private static string RemoveCharAfterVowel(string surname,char c)
        {
            string vowels = "AEIOU";
            surname = surname.ToUpper ();
            for (int i = 0; i < surname.Length - 1; i++)
            {
                if (vowels.Contains(surname[i])
                    && (surname[i + 1] == 'W' || surname[i + 1] == 'H'))
                    surname = surname.Remove(i + 1, 1);
            }
            return surname;
        }
        private static string RemoveVowelsWithA(string surname)
        {
            surname = surname.ToUpper();
            return surname.Replace('E', 'A').Replace('I', 'A').Replace
                ('O', 'A').Replace('U', 'A');
        }

        /// <summary>
        /// New York State Identification and Intelligence System (NYSIIS) Phonetic Encoder
        /// </summary>
        /// <param name="surname"></param>
        /// <returns></returns>
        public static string NYSIIS(this string surname)
        {

            surname = surname.ToUpper();
            surname = Regex.Replace(surname, "[^A-Z]", string.Empty);
            
            
            surname = TranscodePrefix(surname);
            surname = TranscodeSuffix(surname);
            surname = surname[0].ToString () +  RemoveVowelsWithA(surname.Substring (1));
            surname = TranscodeSuffix(surname).StripConsecutiveRepeatChars();

          
            char[] Key = new char[surname.Length];
            int l = 0;
            Key[l] = surname[0];
            l++;
            for (int j = 1; j < surname.Length; j++)
            {
                if (surname[j] == 'E' && surname[j + 1] == 'V')
                {
                    if (Key[l - 1] != 'A')
                    {
                        Key[l] = 'A';
                        Key[l + 1] = 'F';
                        continue;
                    }
                }
               
                if (surname[j] == 'Q')
                {
                    if (Key[l - 1] != 'G')
                    {
                        Key[l] = 'G';
                        l++;
                        continue;
                    }
                }

                if (surname[j] == 'Z')
                {
                    if (Key[l - 1] != 'S')
                    {
                        Key[l] = 'S';
                        l++; continue;
                    }
                }

                if (surname[j] == 'M')
                {
                    if (Key[l - 1] != 'N')
                    {
                        Key[l] = 'N';
                        l++;
                        continue;
                    }
                }

                if (surname[j] == 'K' && surname[j + 1] == 'N')
                {
                    if (Key[l - 1] != 'K')
                    {
                        Key[l] = 'K';
                        l++;
                        continue;
                    }
                }

                if (surname[j] == 'K' && surname[j + 1] != 'N')
                {
                    if (Key[l - 1] != 'C')
                    {
                        Key[l] = 'C';
                        l++;
                        continue;
                    }
                }

                if (surname[j] == 'S' && surname[j + 1] == 'C' && surname[j + 2] == 'H')
                {
                    if (Key[l - 1] != 'S')
                    {
                        Key[l] = 'S';
                        Key[++l] = 'S';
                        Key[++l] = 'S';
                    }
                }

                if (surname[j] == 'P' && surname[j + 1] == 'H')
                {
                    Key[l] = 'F';
                    Key[++l] = 'F';
                }


                if (j < surname.Length - 1 && surname[j] == 'H' && (surname[j + 1].isVowel() == false || surname[j - 1].isVowel() == false))
                {
                    Key[l] = surname[j - 1];
                    l++;
                    continue;
                }

                if (j != 0 && surname[j] == 'W' && (surname[j - 1].isVowel()) == false)
                {
                    Key[l] = surname[j - 1];
                    l++;
                    continue;
                }
                if (Key[l - 1] != surname[j])
                {
                    if ((surname[j].isVowel()) == false)
                    {
                        Key[l] = surname[j];
                        l++;
                        continue;
                    }
                    else
                    {
                        if (Key[l - 1] != 'A')
                        {
                            Key[l] = 'A';
                            l++;
                            continue;
                        }

                    }

                }
            }

            string NYSIISKey = new string(Key);
            
            if (NYSIISKey.IndexOf('\0') != -1)
                return  NYSIISKey.Remove(NYSIISKey.IndexOf('\0'));
            if (NYSIISKey.EndsWith("S") || NYSIISKey.EndsWith("A"))
                return  NYSIISKey.Substring(0, NYSIISKey.Length - 1);
            if (NYSIISKey.EndsWith("AY"))
                return  NYSIISKey.Substring(0, NYSIISKey.Length - 2) + "Y";

            return NYSIISKey;
        }
       

    }
}
